
/*
vgPart.cc
This file is part of opengl-vrml-assembly.
Copyright (C) Rafal Pielech, rafal.pielech@gmail.com

opengl-vrml-assembly is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

opengl-vrml-assembly is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with opengl-vrml-assembly.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <windows.h>
#include <gl/gl.h>
#include <vgDebug.h>
#include <fstream>
#include <cmath>
#include <vgPart.h>

void
vgPart::vgCalcNormal(const float * pt1,
                     const float * pt2,
                     const float * pt3,
                     float       * res)
{
  VG_DEBUG
  //
  float v1[3];
  float v2[3];
  
  v1[0] = pt2[0] - pt1[0];
  v1[1] = pt2[1] - pt1[1];
  v1[2] = pt2[2] - pt1[2];
  
  v2[0] = pt3[0] - pt1[0];
  v2[1] = pt3[1] - pt1[1];
  v2[2] = pt3[2] - pt1[2];
  
  res[0] = (v1[1] * v2[2]) - (v2[1] * v1[2]);
  res[1] = (v2[0] * v1[2]) - (v1[0] * v2[2]);
  res[2] = (v1[0] * v2[1]) - (v2[0] * v1[1]);
  
  float length = sqrt(res[0] * res[0] + res[1] * res[1] + res[2] * res[2]);
  res[0] /= length;
  res[1] /= length;
  res[2] /= length;
}

vgPart::vgPart(void)
{
  VG_DEBUG
}

vgPart::vgPart(const std::string file)
{
  VG_DEBUG
  //
  float    ** vertices;
  unsigned    vertices_count;
  // Triangular faces' data
  unsigned ** faces_t;
  unsigned    faces_t_count;
  // Quadratic faces' data
  unsigned ** faces_q;
  unsigned    faces_q_count;
  // Temporary face's normal vector
  float       tmp_normal_vec[3];
  //
  ifstream input;
  input.open(file.c_str());
  // Take number of points
  if(input.good())
  {
    input >> vertices_count;
    vertices = new float * [vertices_count];
    // Read in the points
    for(unsigned i=0; i<vertices_count; i++)
    {
      vertices[i] = new float [3];
      for(unsigned j=0; j<3; j++)
      {
        input >> vertices[i][j];
      }
    }
    // Read in the faces
    // Are there triangles available?
    input >> faces_t_count;
    if(faces_t_count)
    {
      faces_t = new unsigned * [faces_t_count];
      for(unsigned i=0; i<faces_t_count; i++)
      {
        faces_t[i] = new unsigned [3];
        for(unsigned j=0; j<3; j++)
        {
          input >> faces_t[i][j];
        }
      }
      // Triangles are ready
      // Are there quads available?
      input >> faces_q_count;
      if(faces_q_count)
      {
        faces_q = new unsigned * [faces_q_count];
        for(unsigned i=0; i<faces_q_count; i++)
        {
          faces_q[i] = new unsigned [4];
          for(unsigned j=0; j<4; j++)
          {
            input >> faces_q[i][j];
          }
        }
      }
    }
    // Now create OpenGL display list
    dispList = glGenLists(1);
    glNewList(dispList, GL_COMPILE);
      // Triangles?
      if(faces_t_count)
      {
        glBegin(GL_TRIANGLES);
        for(unsigned i=0; i<faces_t_count; i++)
        {
          // Calculate normal vector of the face
          vgCalcNormal(vertices[faces_t[i][0]],
                       vertices[faces_t[i][1]],
                       vertices[faces_t[i][2]],
                       tmp_normal_vec);
          glNormal3fv(tmp_normal_vec);
          glVertex3fv(vertices[faces_t[i][0]]);
          glVertex3fv(vertices[faces_t[i][1]]);
          glVertex3fv(vertices[faces_t[i][2]]);
        }
        glEnd();
      }
      // Quads?
      if(faces_q_count)
      {
        glBegin(GL_QUADS);
        for(unsigned i=0; i<faces_q_count; i++)
        {
          // Calculate normal vector of the face
          vgCalcNormal(vertices[faces_q[i][0]],
                       vertices[faces_q[i][1]],
                       vertices[faces_q[i][2]],
                       tmp_normal_vec);
          glNormal3fv(tmp_normal_vec);
          glVertex3fv(vertices[faces_q[i][0]]);
          glVertex3fv(vertices[faces_q[i][1]]);
          glVertex3fv(vertices[faces_q[i][2]]);
          glVertex3fv(vertices[faces_q[i][3]]);
        }
        glEnd();
      }
    glEndList();
    // Now do clean-up
    // Vertices
    if(vertices_count)
    {
      for(unsigned i=0; i<vertices_count; i++)
      {
        delete [] vertices[i];
      }
      delete [] vertices;
    }
    // Triangles
    if(faces_t_count)
    {
      for(unsigned i=0; i<faces_t_count; i++)
      {
        delete [] faces_t[i];
      }
      delete [] faces_t;
    }
    // Quads
    if(faces_q_count)
    {
      for(unsigned i=0; i<faces_q_count; i++)
      {
        delete [] faces_q[i];
      }
      delete [] faces_q;
    }
  }
}

void
vgPart::vgDraw() const
{
  glCallList(dispList);
}

vgPart::~vgPart(void)
{
  VG_DEBUG
  glDeleteLists(dispList, 1);
}
